/******************************************************************************* * Copyright (c) 2000, 2011 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * IBM Corporation - initial API and implementation *******************************************************************************/ package org.eclipse.jdt.internal.corext.refactoring.structure; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import org.eclipse.core.runtime.Assert; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.NullProgressMonitor; import org.eclipse.core.runtime.SubProgressMonitor; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IResource; import org.eclipse.text.edits.TextEdit; import org.eclipse.text.edits.TextEditGroup; import org.eclipse.jface.text.BadLocationException; import org.eclipse.jface.text.Document; import org.eclipse.jface.text.IDocument; import org.eclipse.ltk.core.refactoring.Change; import org.eclipse.ltk.core.refactoring.CompositeChange; import org.eclipse.ltk.core.refactoring.RefactoringDescriptor; import org.eclipse.ltk.core.refactoring.RefactoringStatus; import org.eclipse.ltk.core.refactoring.RefactoringStatusContext; import org.eclipse.ltk.core.refactoring.participants.CheckConditionsContext; import org.eclipse.ltk.core.refactoring.participants.MoveArguments; import org.eclipse.ltk.core.refactoring.participants.MoveParticipant; import org.eclipse.ltk.core.refactoring.participants.ParticipantManager; import org.eclipse.ltk.core.refactoring.participants.RefactoringParticipant; import org.eclipse.ltk.core.refactoring.participants.ResourceChangeChecker; import org.eclipse.ltk.core.refactoring.participants.SharableParticipants; import org.eclipse.jdt.core.Flags; import org.eclipse.jdt.core.ICompilationUnit; import org.eclipse.jdt.core.IField; import org.eclipse.jdt.core.IInitializer; import org.eclipse.jdt.core.IJavaElement; import org.eclipse.jdt.core.IJavaProject; import org.eclipse.jdt.core.IMember; import org.eclipse.jdt.core.IMethod; import org.eclipse.jdt.core.ISourceRange; import org.eclipse.jdt.core.IType; import org.eclipse.jdt.core.JavaModelException; import org.eclipse.jdt.core.dom.ASTNode; import org.eclipse.jdt.core.dom.ASTVisitor; import org.eclipse.jdt.core.dom.AbstractTypeDeclaration; import org.eclipse.jdt.core.dom.AnnotationTypeDeclaration; import org.eclipse.jdt.core.dom.BodyDeclaration; import org.eclipse.jdt.core.dom.EnumDeclaration; import org.eclipse.jdt.core.dom.FieldDeclaration; import org.eclipse.jdt.core.dom.IBinding; import org.eclipse.jdt.core.dom.IMethodBinding; import org.eclipse.jdt.core.dom.ITypeBinding; import org.eclipse.jdt.core.dom.IVariableBinding; import org.eclipse.jdt.core.dom.MethodDeclaration; import org.eclipse.jdt.core.dom.Modifier; import org.eclipse.jdt.core.dom.Modifier.ModifierKeyword; import org.eclipse.jdt.core.dom.Name; import org.eclipse.jdt.core.dom.NodeFinder; import org.eclipse.jdt.core.dom.SimpleName; import org.eclipse.jdt.core.dom.TypeDeclaration; import org.eclipse.jdt.core.dom.VariableDeclarationFragment; import org.eclipse.jdt.core.dom.rewrite.ITrackedNodePosition; import org.eclipse.jdt.core.dom.rewrite.ImportRewrite.ImportRewriteContext; import org.eclipse.jdt.core.dom.rewrite.ListRewrite; import org.eclipse.jdt.core.refactoring.IJavaRefactorings; import org.eclipse.jdt.core.refactoring.descriptors.JavaRefactoringDescriptor; import org.eclipse.jdt.core.refactoring.descriptors.MoveStaticMembersDescriptor; import org.eclipse.jdt.core.search.IJavaSearchConstants; import org.eclipse.jdt.core.search.IJavaSearchScope; import org.eclipse.jdt.core.search.SearchMatch; import org.eclipse.jdt.core.search.SearchPattern; import org.eclipse.jdt.internal.core.refactoring.descriptors.RefactoringSignatureDescriptorFactory; import org.eclipse.jdt.internal.corext.codemanipulation.CodeGenerationSettings; import org.eclipse.jdt.internal.corext.codemanipulation.ContextSensitiveImportRewriteContext; import org.eclipse.jdt.internal.corext.dom.ASTNodes; import org.eclipse.jdt.internal.corext.dom.ModifierRewrite; import org.eclipse.jdt.internal.corext.refactoring.Checks; import org.eclipse.jdt.internal.corext.refactoring.CollectingSearchRequestor; import org.eclipse.jdt.internal.corext.refactoring.JDTRefactoringDescriptorComment; import org.eclipse.jdt.internal.corext.refactoring.JavaRefactoringArguments; import org.eclipse.jdt.internal.corext.refactoring.JavaRefactoringDescriptorUtil; import org.eclipse.jdt.internal.corext.refactoring.RefactoringAvailabilityTester; import org.eclipse.jdt.internal.corext.refactoring.RefactoringCoreMessages; import org.eclipse.jdt.internal.corext.refactoring.RefactoringScopeFactory; import org.eclipse.jdt.internal.corext.refactoring.RefactoringSearchEngine; import org.eclipse.jdt.internal.corext.refactoring.RefactoringSearchEngine2; import org.eclipse.jdt.internal.corext.refactoring.SearchResultGroup; import org.eclipse.jdt.internal.corext.refactoring.base.JavaStatusContext; import org.eclipse.jdt.internal.corext.refactoring.base.ReferencesInBinaryContext; import org.eclipse.jdt.internal.corext.refactoring.changes.DynamicValidationRefactoringChange; import org.eclipse.jdt.internal.corext.refactoring.codingspectator.WatchedJavaMoveProcessor; import org.eclipse.jdt.internal.corext.refactoring.delegates.DelegateFieldCreator; import org.eclipse.jdt.internal.corext.refactoring.delegates.DelegateMethodCreator; import org.eclipse.jdt.internal.corext.refactoring.participants.JavaProcessors; import org.eclipse.jdt.internal.corext.refactoring.structure.MemberVisibilityAdjustor.IncomingMemberVisibilityAdjustment; import org.eclipse.jdt.internal.corext.refactoring.tagging.IDelegateUpdating; import org.eclipse.jdt.internal.corext.refactoring.util.JavaElementUtil; import org.eclipse.jdt.internal.corext.util.JavaModelUtil; import org.eclipse.jdt.internal.corext.util.JdtFlags; import org.eclipse.jdt.internal.corext.util.Messages; import org.eclipse.jdt.internal.corext.util.SearchUtils; import org.eclipse.jdt.internal.corext.util.Strings; import org.eclipse.jdt.ui.JavaElementLabels; import org.eclipse.jdt.ui.refactoring.IRefactoringProcessorIds; import org.eclipse.jdt.internal.ui.JavaPlugin; import org.eclipse.jdt.internal.ui.preferences.JavaPreferencesSettings; import org.eclipse.jdt.internal.ui.viewsupport.BasicElementLabels; /** * * @author Mohsen Vakilian, nchen - Provided a method to create a refactoring descriptor. * */ public final class MoveStaticMembersProcessor extends WatchedJavaMoveProcessor implements IDelegateUpdating { private static final String ATTRIBUTE_DELEGATE= "delegate"; //$NON-NLS-1$ private static final String ATTRIBUTE_DEPRECATE= "deprecate"; //$NON-NLS-1$ private static final String TRACKED_POSITION_PROPERTY= "MoveStaticMembersProcessor.trackedPosition"; //$NON-NLS-1$ private IMember[] fMembersToMove; private IType fDestinationType; private String fDestinationTypeName; private CodeGenerationSettings fPreferences; private CompositeChange fChange; private CompilationUnitRewrite fSource; private ITypeBinding fSourceBinding; private CompilationUnitRewrite fTarget; private IBinding[] fMemberBindings; private BodyDeclaration[] fMemberDeclarations; private boolean fDelegateUpdating; private boolean fDelegateDeprecation; private static class TypeReferenceFinder extends ASTVisitor { List<IBinding> fResult= new ArrayList<IBinding>(); Set<ITypeBinding> fDefined= new HashSet<ITypeBinding>(); public static List<IBinding> perform(ASTNode root) { TypeReferenceFinder visitor= new TypeReferenceFinder(); root.accept(visitor); return visitor.fResult; } @Override public boolean visit(TypeDeclaration node) { fDefined.add(node.resolveBinding()); return true; } @Override public boolean visit(SimpleName node) { IBinding binding= node.resolveBinding(); if (!(binding instanceof ITypeBinding)) return true; if (!fDefined.contains(binding)) fResult.add(binding); return true; } @Override public boolean visit(AnnotationTypeDeclaration node) { fDefined.add(node.resolveBinding()); return true; } @Override public boolean visit(EnumDeclaration node) { fDefined.add(node.resolveBinding()); return true; } } /** * Creates a new move static members processor. * * @param members the members to move, or <code>null</code> if invoked by scripting * @param settings the code generation settings, or <code>null</code> if invoked by scripting */ public MoveStaticMembersProcessor(IMember[] members, CodeGenerationSettings settings) { fMembersToMove= members; fPreferences= settings; fDelegateUpdating= false; fDelegateDeprecation= true; } public MoveStaticMembersProcessor(JavaRefactoringArguments arguments, RefactoringStatus status) { fDelegateUpdating= false; fDelegateDeprecation= true; RefactoringStatus initializeStatus= initialize(arguments); status.merge(initializeStatus); } /** * {@inheritDoc} */ @Override public boolean isApplicable() throws CoreException { return RefactoringAvailabilityTester.isMoveStaticMembersAvailable(fMembersToMove); } /** * {@inheritDoc} */ @Override public Object[] getElements() { Object[] result= new Object[fMembersToMove.length]; System.arraycopy(fMembersToMove, 0, result, 0, fMembersToMove.length); return result; } /** * {@inheritDoc} */ @Override public String getIdentifier() { return IRefactoringProcessorIds.MOVE_STATIC_MEMBERS_PROCESSOR; } /** * {@inheritDoc} */ @Override public RefactoringParticipant[] loadParticipants(RefactoringStatus status, SharableParticipants sharedParticipants) throws CoreException { List<MoveParticipant> result= new ArrayList<MoveParticipant>(); MoveArguments args= new MoveArguments(fDestinationType, true); String[] natures= JavaProcessors.computeAffectedNaturs(fMembersToMove); for (int i= 0; i < fMembersToMove.length; i++) { IMember member= fMembersToMove[i]; result.addAll(Arrays.asList(ParticipantManager.loadMoveParticipants( status, this, member, args, natures, sharedParticipants))); } return result.toArray(new RefactoringParticipant[result.size()]); } //------------------- IDelegateUpdating ---------------------- public boolean canEnableDelegateUpdating() { try { for (int i= 0; i < fMembersToMove.length; i++) { if (isDelegateCreationAvailable(fMembersToMove[i])) return true; } } catch (JavaModelException e) { return false; } return false; } private boolean isDelegateCreationAvailable(IMember member) throws JavaModelException { if (member instanceof IMethod) return true; if (member instanceof IField && RefactoringAvailabilityTester.isDelegateCreationAvailable(((IField) member))) return true; return false; } public boolean getDelegateUpdating() { return fDelegateUpdating; } public void setDelegateUpdating(boolean updating) { fDelegateUpdating= updating; } public boolean getDeprecateDelegates() { return fDelegateDeprecation; } public void setDeprecateDelegates(boolean deprecate) { fDelegateDeprecation= deprecate; } @Override public String getProcessorName() { return RefactoringCoreMessages.MoveMembersRefactoring_Move_Members; } public IType getDestinationType() { return fDestinationType; } public void setDestinationTypeFullyQualifiedName(String fullyQualifiedTypeName) throws JavaModelException { Assert.isNotNull(fullyQualifiedTypeName); fDestinationType= resolveType(fullyQualifiedTypeName); //workaround for bug 36032: IJavaProject#findType(..) doesn't find secondary type fDestinationTypeName= fullyQualifiedTypeName; } public IMember[] getMembersToMove() { return fMembersToMove; } public IType getDeclaringType() { //all methods declared in same type - checked in precondition return fMembersToMove[0].getDeclaringType(); //index safe - checked in areAllMoveable() } private IType resolveType(String qualifiedTypeName) throws JavaModelException { IType type= getDeclaringType().getJavaProject().findType(qualifiedTypeName); if (type == null) type= getDeclaringType().getJavaProject().findType(getDeclaringType().getPackageFragment().getElementName(), qualifiedTypeName); return type; } //---- Activation checking ------------------------------------ @Override public RefactoringStatus checkInitialConditions(IProgressMonitor pm) throws CoreException { try { pm.beginTask(RefactoringCoreMessages.MoveMembersRefactoring_checking, 1); RefactoringStatus result= new RefactoringStatus(); result.merge(checkDeclaringType()); pm.worked(1); if (result.hasFatalError()) return result; fSource= new CompilationUnitRewrite(fMembersToMove[0].getCompilationUnit()); fSourceBinding= (ITypeBinding) ((SimpleName) NodeFinder.perform(fSource.getRoot(), fMembersToMove[0].getDeclaringType().getNameRange())).resolveBinding(); fMemberBindings= getMemberBindings(); if (fSourceBinding == null || hasUnresolvedMemberBinding()) { result.addFatalError(Messages.format( RefactoringCoreMessages.MoveMembersRefactoring_compile_errors, BasicElementLabels.getFileName(fSource.getCu()))); } fMemberDeclarations= getASTMembers(result); return result; } finally { pm.done(); } } private boolean hasUnresolvedMemberBinding() { for (int i= 0; i < fMemberBindings.length; i++) { if (fMemberBindings[i] == null) return true; } return false; } private RefactoringStatus checkDeclaringType() { IType declaringType= getDeclaringType(); if (declaringType.getFullyQualifiedName('.').equals("java.lang.Object")) //$NON-NLS-1$ return RefactoringStatus.createFatalErrorStatus(RefactoringCoreMessages.MoveMembersRefactoring_Object); if (declaringType.isBinary()) return RefactoringStatus.createFatalErrorStatus(RefactoringCoreMessages.MoveMembersRefactoring_binary); if (declaringType.isReadOnly()) return RefactoringStatus.createFatalErrorStatus(RefactoringCoreMessages.MoveMembersRefactoring_read_only); return null; } //---- Input checking ------------------------------------ @Override public RefactoringStatus checkFinalConditions(IProgressMonitor pm, CheckConditionsContext context) throws CoreException { fTarget= null; try { pm.beginTask(RefactoringCoreMessages.MoveMembersRefactoring_checking, 10); RefactoringStatus result= new RefactoringStatus(); fSource.clearASTAndImportRewrites(); result.merge(checkDestinationType()); if (result.hasFatalError()) return result; result.merge(checkDestinationInsideTypeToMove()); if (result.hasFatalError()) return result; result.merge(MemberCheckUtil.checkMembersInDestinationType(fMembersToMove, fDestinationType)); if (result.hasFatalError()) return result; result.merge(checkNativeMovedMethods(new SubProgressMonitor(pm, 1))); if (result.hasFatalError()) return result; List<ICompilationUnit> modifiedCus= new ArrayList<ICompilationUnit>(); createChange(modifiedCus, result, new SubProgressMonitor(pm, 7)); IFile[] changedFiles= getAllFilesToModify(modifiedCus); ResourceChangeChecker checker= (ResourceChangeChecker) context.getChecker(ResourceChangeChecker.class); for (int i= 0; i < changedFiles.length; i++) { checker.getDeltaFactory().change(changedFiles[i]); } return result; } finally { pm.done(); } } private IFile[] getAllFilesToModify(List<ICompilationUnit> modifiedCus) { Set<IResource> result= new HashSet<IResource>(); IResource resource= fDestinationType.getCompilationUnit().getResource(); result.add(resource); for (int i= 0; i < fMembersToMove.length; i++) { resource= fMembersToMove[i].getCompilationUnit().getResource(); if (resource != null) result.add(resource); } for (Iterator<ICompilationUnit> iter= modifiedCus.iterator(); iter.hasNext();) { ICompilationUnit unit= iter.next(); if (unit.getResource() != null) result.add(unit.getResource()); } return result.toArray(new IFile[result.size()]); } private RefactoringStatus checkDestinationType() throws JavaModelException { if (fDestinationType == null) { String message= Messages.format(RefactoringCoreMessages.MoveMembersRefactoring_not_found, BasicElementLabels.getJavaElementName(fDestinationTypeName)); return RefactoringStatus.createFatalErrorStatus(message); } if (fDestinationType.equals(getDeclaringType())) { String message= Messages.format(RefactoringCoreMessages.MoveMembersRefactoring_same, JavaElementUtil.createSignature(fDestinationType)); return RefactoringStatus.createFatalErrorStatus(message); } if (!fDestinationType.exists()) { String message= Messages.format(RefactoringCoreMessages.MoveMembersRefactoring_not_exist, JavaElementUtil.createSignature(fDestinationType)); return RefactoringStatus.createFatalErrorStatus(message); } if (fDestinationType.isBinary()) { String message= Messages.format(RefactoringCoreMessages.MoveMembersRefactoring_dest_binary, JavaElementUtil.createSignature(fDestinationType)); return RefactoringStatus.createFatalErrorStatus(message); } RefactoringStatus result= new RefactoringStatus(); if (fDestinationType.isInterface() && !getDeclaringType().isInterface()) result.merge(checkFieldsForInterface()); if (result.hasFatalError()) return result; // no checking required for moving interface fields to classes if (!(JdtFlags.isStatic(fDestinationType) || fDestinationType.getDeclaringType() == null)) { String message= RefactoringCoreMessages.MoveMembersRefactoring_static_declaration; result.addError(message); } return result; } private RefactoringStatus checkDestinationInsideTypeToMove() throws JavaModelException { RefactoringStatus result= new RefactoringStatus(); for (int i= 0; i < fMembersToMove.length; i++) { if (!(fMembersToMove[i] instanceof IType)) continue; IType type= (IType) fMembersToMove[i]; if (fDestinationType.equals(type) || JavaElementUtil.isAncestorOf(type, fDestinationType)) { String message= Messages.format(RefactoringCoreMessages.MoveMembersRefactoring_inside, new String[] { getQualifiedTypeLabel(type), getQualifiedTypeLabel(fDestinationType) }); RefactoringStatusContext context= JavaStatusContext.create(fDestinationType.getCompilationUnit(), fDestinationType.getNameRange()); result.addFatalError(message, context); return result; } } return result; } private RefactoringStatus checkFieldsForInterface() throws JavaModelException { //could be more clever and make field final if it is only written once... RefactoringStatus result= new RefactoringStatus(); for (int i= 0; i < fMembersToMove.length; i++) { if (!canMoveToInterface(fMembersToMove[i])) { String message= RefactoringCoreMessages.MoveMembersRefactoring_only_public_static; result.addError(message, JavaStatusContext.create(fMembersToMove[i])); } } return result; } private boolean canMoveToInterface(IMember member) throws JavaModelException { int flags= member.getFlags(); switch (member.getElementType()) { case IJavaElement.FIELD: if (!(Flags.isPublic(flags) && Flags.isStatic(flags) && Flags.isFinal(flags))) return false; if (Flags.isEnum(flags)) return false; VariableDeclarationFragment declaration= ASTNodeSearchUtil.getFieldDeclarationFragmentNode((IField) member, fSource.getRoot()); if (declaration != null) return declaration.getInitializer() != null; return false; case IJavaElement.TYPE: { IType type= (IType) member; if (type.isInterface() && !Checks.isTopLevel(type)) return true; return Flags.isPublic(flags) && Flags.isStatic(flags); } default: return false; } } private RefactoringStatus checkMovedMemberAvailability(IMember memberToMove, IProgressMonitor pm) throws JavaModelException { RefactoringStatus result= new RefactoringStatus(); if (memberToMove instanceof IType) { // recursively check accessibility of member type's members IJavaElement[] typeMembers= ((IType) memberToMove).getChildren(); pm.beginTask(RefactoringCoreMessages.MoveMembersRefactoring_checking, typeMembers.length + 1); for (int i= 0; i < typeMembers.length; i++) { if (typeMembers[i] instanceof IInitializer) pm.worked(1); else result.merge(checkMovedMemberAvailability((IMember) typeMembers[i], new SubProgressMonitor(pm, 1))); } } else { pm.beginTask(RefactoringCoreMessages.MoveMembersRefactoring_checking, 1); } IType[] blindAccessorTypes= getTypesNotSeeingMovedMember(memberToMove, new SubProgressMonitor(pm, 1), result); for (int k= 0; k < blindAccessorTypes.length; k++) { String message= createNonAccessibleMemberMessage(memberToMove, blindAccessorTypes[k],/*moved*/true); result.addError(message, JavaStatusContext.create(memberToMove)); } pm.done(); return result; } private IType[] getTypesNotSeeingMovedMember(IMember member, IProgressMonitor pm, RefactoringStatus status) throws JavaModelException { if (JdtFlags.isPublic(member) && JdtFlags.isPublic(fDestinationType)) return new IType[0]; HashSet<IType> blindAccessorTypes= new HashSet<IType>(); // referencing, but access to destination type illegal SearchResultGroup[] references= getReferences(member, new SubProgressMonitor(pm, 1), status); for (int i= 0; i < references.length; i++) { SearchMatch[] searchResults= references[i].getSearchResults(); for (int k= 0; k < searchResults.length; k++) { SearchMatch searchResult= searchResults[k]; IJavaElement element= SearchUtils.getEnclosingJavaElement(searchResult); IType type= (IType) element.getAncestor(IJavaElement.TYPE); if (type != null //reference can e.g. be an import declaration && !blindAccessorTypes.contains(type) && !isWithinMemberToMove(searchResult) && !isVisibleFrom(getDestinationType(), type)) { blindAccessorTypes.add(type); } } } if (fDelegateUpdating && isDelegateCreationAvailable(member)) { // ensure moved member is visible from the delegate IType type= member.getDeclaringType(); if (!blindAccessorTypes.contains(type) && !isVisibleFrom(getDestinationType(), type)) blindAccessorTypes.add(type); } return blindAccessorTypes.toArray(new IType[blindAccessorTypes.size()]); } private String createNonAccessibleMemberMessage(IMember member, IType accessingType, boolean moved) { //Non-visibility can have various reasons and always displaying all visibility //flags for all enclosing elements would be too heavy. Context reveals exact cause. IType declaringType= moved ? getDestinationType() : getDeclaringType(); String message; switch (member.getElementType()) { case IJavaElement.FIELD: { if (moved) message= Messages.format(RefactoringCoreMessages.MoveMembersRefactoring_moved_field, new String[] { JavaElementUtil.createFieldSignature((IField) member), getQualifiedTypeLabel(accessingType), getQualifiedTypeLabel(declaringType) }); else message= Messages.format(RefactoringCoreMessages.MoveMembersRefactoring_accessed_field, new String[] { JavaElementUtil.createFieldSignature((IField) member), getQualifiedTypeLabel(accessingType) }); return message; } case IJavaElement.METHOD: { if (moved) message= Messages.format(RefactoringCoreMessages.MoveMembersRefactoring_moved_method, new String[] { JavaElementUtil.createMethodSignature((IMethod) member), getQualifiedTypeLabel(accessingType), getQualifiedTypeLabel(declaringType) }); else message= Messages.format(RefactoringCoreMessages.MoveMembersRefactoring_accessed_method, new String[] { JavaElementUtil.createMethodSignature((IMethod) member), getQualifiedTypeLabel(accessingType) }); return message; } case IJavaElement.TYPE: { if (moved) message= Messages.format(RefactoringCoreMessages.MoveMembersRefactoring_moved_type, new String[] { getQualifiedTypeLabel((IType) member), getQualifiedTypeLabel(accessingType), getQualifiedTypeLabel(declaringType) }); else message= Messages.format(RefactoringCoreMessages.MoveMembersRefactoring_accessed_type, new String[] { getQualifiedTypeLabel((IType) member), getQualifiedTypeLabel(accessingType) }); return message; } default: Assert.isTrue(false); return null; } } private String getQualifiedTypeLabel(IType accessingType) { //CODINGSPECTATOR: If the destination type entered by user is invalid, put generate an error message to be put in the header of the descriptor. if (accessingType == null) { return String.format("CODINGSPECTATOR:Type not found:%s", new String[] { fDestinationTypeName }); //$NON-NLS-1$ } return BasicElementLabels.getJavaCodeString(accessingType.getFullyQualifiedName('.')); } private static SearchResultGroup[] getReferences(IMember member, IProgressMonitor monitor, RefactoringStatus status) throws JavaModelException { final RefactoringSearchEngine2 engine= new RefactoringSearchEngine2(SearchPattern.createPattern(member, IJavaSearchConstants.REFERENCES, SearchUtils.GENERICS_AGNOSTIC_MATCH_RULE)); engine.setFiltering(true, true); engine.setScope(RefactoringScopeFactory.create(member)); engine.setStatus(status); engine.searchPattern(new SubProgressMonitor(monitor, 1)); return (SearchResultGroup[]) engine.getResults(); } private static boolean isVisibleFrom(IType newMemberDeclaringType, IType accessingType) throws JavaModelException { int memberVisibility= JdtFlags.getVisibilityCode(newMemberDeclaringType); IType declaringType= newMemberDeclaringType.getDeclaringType(); while (declaringType != null) { //get lowest visibility in all parent types of newMemberDeclaringType memberVisibility= JdtFlags.getLowerVisibility( memberVisibility, JdtFlags.getVisibilityCode(declaringType)); declaringType= declaringType.getDeclaringType(); } switch (memberVisibility) { case Modifier.PRIVATE: return isEqualOrEnclosedType(accessingType, newMemberDeclaringType); case Modifier.NONE: return JavaModelUtil.isSamePackage(accessingType.getPackageFragment(), newMemberDeclaringType.getPackageFragment()); case Modifier.PROTECTED: return JavaModelUtil.isSamePackage(accessingType.getPackageFragment(), newMemberDeclaringType.getPackageFragment()) || accessingType.newSupertypeHierarchy(null).contains(newMemberDeclaringType); case Modifier.PUBLIC: return true; default: Assert.isTrue(false); return false; } } private static boolean isEqualOrEnclosedType(IType inner, IType outer) { while (inner != null) { if (inner.equals(outer)) return true; else inner= inner.getDeclaringType(); } return false; } private boolean isWithinMemberToMove(SearchMatch result) throws JavaModelException { ICompilationUnit referenceCU= SearchUtils.getCompilationUnit(result); if (!referenceCU.equals(fSource.getCu())) return false; int referenceStart= result.getOffset(); for (int i= 0; i < fMembersToMove.length; i++) { ISourceRange range= fMembersToMove[i].getSourceRange(); if (range.getOffset() <= referenceStart && range.getOffset() + range.getLength() >= referenceStart) return true; } return false; } private RefactoringStatus checkNativeMovedMethods(IProgressMonitor pm) throws JavaModelException { pm.beginTask(RefactoringCoreMessages.MoveMembersRefactoring_checking, fMembersToMove.length); RefactoringStatus result= new RefactoringStatus(); for (int i= 0; i < fMembersToMove.length; i++) { if (fMembersToMove[i].getElementType() != IJavaElement.METHOD) continue; if (!JdtFlags.isNative(fMembersToMove[i])) continue; String message= Messages.format(RefactoringCoreMessages.MoveMembersRefactoring_native, JavaElementUtil.createMethodSignature((IMethod) fMembersToMove[i])); result.addWarning(message, JavaStatusContext.create(fMembersToMove[i])); pm.worked(1); } pm.done(); return result; } @Override public Change createChange(IProgressMonitor pm) throws CoreException { pm.done(); return fChange; } private void createChange(List<ICompilationUnit> modifiedCus, RefactoringStatus status, IProgressMonitor monitor) throws CoreException { monitor.beginTask(RefactoringCoreMessages.MoveMembersRefactoring_creating, 5); fChange= new DynamicValidationRefactoringChange(createDescriptor(), RefactoringCoreMessages.MoveMembersRefactoring_move_members); fTarget= getCuRewrite(fDestinationType.getCompilationUnit()); ITypeBinding targetBinding= getDestinationBinding(); if (targetBinding == null) { status.addFatalError(Messages.format(RefactoringCoreMessages.MoveMembersRefactoring_compile_errors, BasicElementLabels.getFileName(fTarget.getCu()))); monitor.done(); return; } try { Map<IMember, IncomingMemberVisibilityAdjustment> adjustments= new HashMap<IMember, IncomingMemberVisibilityAdjustment>(); IMember member= null; SubProgressMonitor sub= new SubProgressMonitor(monitor, 1, SubProgressMonitor.SUPPRESS_SUBTASK_LABEL); sub.beginTask(RefactoringCoreMessages.MoveMembersRefactoring_creating, fMembersToMove.length); Set<IMember> rewritten= new HashSet<IMember>(); for (int index= 0; index < fMembersToMove.length; index++) { member= fMembersToMove[index]; final MemberVisibilityAdjustor adjustor= new MemberVisibilityAdjustor(fDestinationType, member); adjustor.setAdjustments(adjustments); adjustor.setStatus(status); adjustor.setVisibilitySeverity(RefactoringStatus.WARNING); adjustor.setFailureSeverity(RefactoringStatus.WARNING); adjustor.setRewrite(fSource.getASTRewrite(), fSource.getRoot()); adjustor.adjustVisibility(new NullProgressMonitor()); if (fDelegateUpdating && isDelegateCreationAvailable(member)) { // Add a visibility adjustment so the moved member // will be visible from within the delegate ModifierKeyword threshold= adjustor.getVisibilityThreshold(member, fDestinationType, new NullProgressMonitor()); IncomingMemberVisibilityAdjustment adjustment= adjustments.get(member); ModifierKeyword kw= adjustment != null ? adjustment.getKeyword() : ModifierKeyword.fromFlagValue(JdtFlags.getVisibilityCode(member)); if (MemberVisibilityAdjustor.hasLowerVisibility(kw, threshold)) { adjustments.put( member, new MemberVisibilityAdjustor.IncomingMemberVisibilityAdjustment(member, threshold, RefactoringStatus.createWarningStatus( Messages.format(MemberVisibilityAdjustor.getMessage(member), new String[] { MemberVisibilityAdjustor.getLabel(member), MemberVisibilityAdjustor.getLabel(threshold) }), JavaStatusContext.create(member)))); } } // Check if destination type is visible from references -> // error message if not (for example, when moving into a private type) status.merge(checkMovedMemberAvailability(member, new SubProgressMonitor(sub, 1))); // Put rewrite info into code and into status for (final Iterator<IMember> iterator= rewritten.iterator(); iterator.hasNext();) { adjustments.remove(iterator.next()); } rewritten.addAll(adjustments.keySet()); adjustor.rewriteVisibility(new NullProgressMonitor()); } // First update references in moved members, in order to extract the // source. String[] memberSources= getUpdatedMemberSource(status, fMemberDeclarations, targetBinding); monitor.worked(1); if (status.hasFatalError()) return; ReferencesInBinaryContext binaryRefs= new ReferencesInBinaryContext(RefactoringCoreMessages.ReferencesInBinaryContext_ref_in_binaries_description_plural); IJavaSearchScope scope= RefactoringScopeFactory.create(fMembersToMove, false); SearchPattern pattern= RefactoringSearchEngine.createOrPattern(fMembersToMove, IJavaSearchConstants.ALL_OCCURRENCES); final HashSet<ICompilationUnit> affectedCompilationUnits= new HashSet<ICompilationUnit>(); CollectingSearchRequestor requestor= new CollectingSearchRequestor(binaryRefs) { private ICompilationUnit fLastCU; @Override public void acceptSearchMatch(SearchMatch match) throws CoreException { if (filterMatch(match)) return; if (match.getAccuracy() == SearchMatch.A_INACCURATE) return; ICompilationUnit unit= SearchUtils.getCompilationUnit(match); if (unit != null && !unit.equals(fLastCU)) { fLastCU= unit; affectedCompilationUnits.add(unit); } } }; RefactoringSearchEngine.search(pattern, scope, requestor, new NullProgressMonitor(), status); binaryRefs.addErrorIfNecessary(status); ICompilationUnit[] units= affectedCompilationUnits.toArray(new ICompilationUnit[affectedCompilationUnits.size()]); modifiedCus.addAll(Arrays.asList(units)); final MemberVisibilityAdjustor adjustor= new MemberVisibilityAdjustor(fDestinationType, fDestinationType); sub= new SubProgressMonitor(monitor, 1); sub.beginTask(RefactoringCoreMessages.MoveMembersRefactoring_creating, units.length); for (int index= 0; index < units.length; index++) { ICompilationUnit unit= units[index]; CompilationUnitRewrite rewrite= getCuRewrite(unit); adjustor.setRewrites(Collections.singletonMap(unit, rewrite)); adjustor.setAdjustments(adjustments); adjustor.rewriteVisibility(unit, new SubProgressMonitor(sub, 1)); ReferenceAnalyzer analyzer= new ReferenceAnalyzer(rewrite, fMemberBindings, targetBinding, fSourceBinding); rewrite.getRoot().accept(analyzer); status.merge(analyzer.getStatus()); if (status.hasFatalError()) { fChange= null; return; } if (!(fSource.getCu().equals(unit) || fTarget.getCu().equals(unit))) fChange.add(rewrite.createChange(true)); } status.merge(moveMembers(fMemberDeclarations, memberSources)); fChange.add(fSource.createChange(true)); modifiedCus.add(fSource.getCu()); if (!fSource.getCu().equals(fTarget.getCu())) { fChange.add(fTarget.createChange(true)); modifiedCus.add(fTarget.getCu()); } monitor.worked(1); } catch (BadLocationException exception) { JavaPlugin.log(exception); } } private MoveStaticMembersDescriptor createDescriptor() { final IMember[] members= getMembersToMove(); String project= null; final IJavaProject javaProject= getDeclaringType().getJavaProject(); if (javaProject != null) project= javaProject.getElementName(); String header= null; if (members.length == 1) header= Messages.format(RefactoringCoreMessages.MoveStaticMembersProcessor_descriptor_description_single, new String[] { JavaElementLabels.getElementLabel(members[0], JavaElementLabels.ALL_FULLY_QUALIFIED), getQualifiedTypeLabel(fDestinationType) }); else header= Messages.format(RefactoringCoreMessages.MoveStaticMembersProcessor_descriptor_description_multi, new String[] { String.valueOf(members.length), getQualifiedTypeLabel(fDestinationType) }); int flags= JavaRefactoringDescriptor.JAR_MIGRATION | JavaRefactoringDescriptor.JAR_REFACTORING | RefactoringDescriptor.STRUCTURAL_CHANGE | RefactoringDescriptor.MULTI_CHANGE; final IType declaring= members[0].getDeclaringType(); try { if (declaring.isLocal() || declaring.isAnonymous()) flags|= JavaRefactoringDescriptor.JAR_SOURCE_ATTACHMENT; } catch (JavaModelException exception) { JavaPlugin.log(exception); } final String description= members.length == 1 ? Messages.format(RefactoringCoreMessages.MoveStaticMembersProcessor_description_descriptor_short_multi, BasicElementLabels.getJavaElementName(members[0].getElementName())) : RefactoringCoreMessages.MoveMembersRefactoring_move_members; final JDTRefactoringDescriptorComment comment= new JDTRefactoringDescriptorComment(project, this, header); comment.addSetting(Messages.format(RefactoringCoreMessages.MoveStaticMembersProcessor_target_element_pattern, getQualifiedTypeLabel(fDestinationType))); final MoveStaticMembersDescriptor descriptor= RefactoringSignatureDescriptorFactory.createMoveStaticMembersDescriptor(); descriptor.setProject(project); descriptor.setDescription(description); descriptor.setComment(comment.asString()); descriptor.setFlags(flags); //CODINGSPECTATOR: If the destination type is valid we put it in the descriptor, otherwise we use the type of one of the selected members. We have to put some type as the destination type of the descriptor for it checks for the non-nullness of this field. if (fDestinationType != null) { descriptor.setDestinationType(fDestinationType); } else { descriptor.setDestinationType(members[0].getDeclaringType()); } descriptor.setKeepOriginal(fDelegateUpdating); descriptor.setDeprecateDelegate(fDelegateDeprecation); descriptor.setMembers(members); return descriptor; } private CompilationUnitRewrite getCuRewrite(ICompilationUnit unit) { if (fSource.getCu().equals(unit)) return fSource; if (fTarget != null && fTarget.getCu().equals(unit)) return fTarget; return new CompilationUnitRewrite(unit); } private AbstractTypeDeclaration getDestinationNode() throws JavaModelException { AbstractTypeDeclaration destination= (AbstractTypeDeclaration) ASTNodes.getParent( NodeFinder.perform(fTarget.getRoot(), fDestinationType.getNameRange()), AbstractTypeDeclaration.class); return destination; } private ITypeBinding getDestinationBinding() throws JavaModelException { ASTNode node= NodeFinder.perform(fTarget.getRoot(), fDestinationType.getNameRange()); if (!(node instanceof SimpleName)) return null; IBinding binding= ((SimpleName) node).resolveBinding(); if (!(binding instanceof ITypeBinding)) return null; return (ITypeBinding) binding; } private IBinding[] getMemberBindings() throws JavaModelException { IBinding[] result= new IBinding[fMembersToMove.length]; for (int i= 0; i < fMembersToMove.length; i++) { IMember member= fMembersToMove[i]; SimpleName name= (SimpleName) NodeFinder.perform(fSource.getRoot(), member.getNameRange()); result[i]= name.resolveBinding(); } return result; } private String[] getUpdatedMemberSource(RefactoringStatus status, BodyDeclaration[] members, ITypeBinding target) throws CoreException, BadLocationException { List<IBinding> typeRefs= new ArrayList<IBinding>(); boolean targetNeedsSourceImport= false; boolean isSourceNotTarget= fSource != fTarget; Set<IBinding> exclude= new HashSet<IBinding>(); for (int i= 0; i < members.length; i++) { BodyDeclaration declaration= members[i]; if (declaration instanceof AbstractTypeDeclaration) { AbstractTypeDeclaration type= (AbstractTypeDeclaration) declaration; ITypeBinding binding= type.resolveBinding(); if (binding != null) exclude.add(binding); } else if (declaration instanceof MethodDeclaration) { MethodDeclaration method= (MethodDeclaration) declaration; IMethodBinding binding= method.resolveBinding(); if (binding != null) exclude.add(binding); } else if (declaration instanceof FieldDeclaration) { FieldDeclaration field= (FieldDeclaration) declaration; for (final Iterator<VariableDeclarationFragment> iterator= field.fragments().iterator(); iterator.hasNext();) { VariableDeclarationFragment fragment= iterator.next(); IVariableBinding binding= fragment.resolveBinding(); if (binding != null) exclude.add(binding); } } } ImportRewriteContext context= new ContextSensitiveImportRewriteContext(getDestinationNode(), fTarget.getImportRewrite()); for (int i= 0; i < members.length; i++) { BodyDeclaration declaration= members[i]; if (isSourceNotTarget) typeRefs.addAll(TypeReferenceFinder.perform(declaration)); MovedMemberAnalyzer analyzer= new MovedMemberAnalyzer(fSource, fMemberBindings, fSourceBinding, target); declaration.accept(analyzer); ImportRewriteUtil.addImports(fTarget, context, declaration, new HashMap<Name, String>(), new HashMap<Name, String>(), exclude, false); if (getDeclaringType().isInterface() && !fDestinationType.isInterface()) { if (declaration instanceof FieldDeclaration) { FieldDeclaration fieldDecl= (FieldDeclaration) declaration; int psfModifiers= Modifier.PUBLIC | Modifier.STATIC | Modifier.FINAL; if ((fieldDecl.getModifiers() & psfModifiers) != psfModifiers) { ModifierRewrite.create(fSource.getASTRewrite(), fieldDecl).setModifiers(psfModifiers, null); } } else if (declaration instanceof AbstractTypeDeclaration) { AbstractTypeDeclaration typeDecl= (AbstractTypeDeclaration) declaration; int psModifiers= Modifier.PUBLIC | Modifier.STATIC; if ((typeDecl.getModifiers() & psModifiers) != psModifiers) { ModifierRewrite.create(fSource.getASTRewrite(), typeDecl).setModifiers(typeDecl.getModifiers() | psModifiers, null); } } } ITrackedNodePosition trackedPosition= fSource.getASTRewrite().track(declaration); declaration.setProperty(TRACKED_POSITION_PROPERTY, trackedPosition); targetNeedsSourceImport|= analyzer.targetNeedsSourceImport(); status.merge(analyzer.getStatus()); } // Adjust imports if (targetNeedsSourceImport && isSourceNotTarget) { fTarget.getImportRewrite().addImport(fSourceBinding, context); } if (isSourceNotTarget) { for (Iterator<IBinding> iter= typeRefs.iterator(); iter.hasNext();) { ITypeBinding binding= (ITypeBinding) iter.next(); fTarget.getImportRewrite().addImport(binding, context); } } // extract updated members String[] updatedMemberSources= new String[members.length]; IDocument document= new Document(fSource.getCu().getBuffer().getContents()); TextEdit edit= fSource.getASTRewrite().rewriteAST(document, fSource.getCu().getJavaProject().getOptions(true)); edit.apply(document, TextEdit.UPDATE_REGIONS); for (int i= 0; i < members.length; i++) { updatedMemberSources[i]= getUpdatedMember(document, members[i]); } fSource.clearASTRewrite(); return updatedMemberSources; } private String getUpdatedMember(IDocument document, BodyDeclaration declaration) throws BadLocationException { ITrackedNodePosition trackedPosition= (ITrackedNodePosition) declaration.getProperty(TRACKED_POSITION_PROPERTY); return Strings.trimIndentation(document.get(trackedPosition.getStartPosition(), trackedPosition.getLength()), fPreferences.tabWidth, fPreferences.indentWidth, false); } private RefactoringStatus moveMembers(BodyDeclaration[] members, String[] sources) throws CoreException { RefactoringStatus result= new RefactoringStatus(); AbstractTypeDeclaration destination= getDestinationNode(); ListRewrite containerRewrite= fTarget.getASTRewrite().getListRewrite(destination, destination.getBodyDeclarationsProperty()); TextEditGroup delete= fSource.createGroupDescription(RefactoringCoreMessages.MoveMembersRefactoring_deleteMembers); TextEditGroup add= fTarget.createGroupDescription(RefactoringCoreMessages.MoveMembersRefactoring_addMembers); for (int i= 0; i < members.length; i++) { BodyDeclaration declaration= members[i]; ASTNode removeImportsOf= null; boolean addedDelegate= false; if (fDelegateUpdating) { if (declaration instanceof MethodDeclaration) { DelegateMethodCreator creator= new DelegateMethodCreator(); creator.setDeclaration(declaration); creator.setDeclareDeprecated(fDelegateDeprecation); creator.setSourceRewrite(fSource); creator.setCopy(false); creator.setNewLocation(getDestinationBinding()); creator.prepareDelegate(); creator.createEdit(); removeImportsOf= ((MethodDeclaration) declaration).getBody(); addedDelegate= true; } if (declaration instanceof FieldDeclaration) { // Note: this FieldDeclaration only has one fragment (@see #getASTMembers(RefactoringStatus)) final VariableDeclarationFragment frag= (VariableDeclarationFragment) ((FieldDeclaration) declaration).fragments().get(0); if (!Modifier.isFinal(declaration.getModifiers())) { // Don't create a delegate for non-final fields result.addInfo( Messages.format(RefactoringCoreMessages.DelegateCreator_cannot_create_field_delegate_not_final, BasicElementLabels.getJavaElementName(frag.getName().getIdentifier())), null); } else if (frag.getInitializer() == null) { // Don't create a delegate without an initializer. result.addInfo( Messages.format(RefactoringCoreMessages.DelegateCreator_cannot_create_field_delegate_no_initializer, BasicElementLabels.getJavaElementName(frag.getName().getIdentifier())), null); } else { DelegateFieldCreator creator= new DelegateFieldCreator(); creator.setDeclaration(declaration); creator.setDeclareDeprecated(fDelegateDeprecation); creator.setSourceRewrite(fSource); creator.setCopy(false); creator.setNewLocation(getDestinationBinding()); creator.prepareDelegate(); creator.createEdit(); removeImportsOf= frag.getInitializer(); addedDelegate= true; } } if (declaration instanceof AbstractTypeDeclaration) { result.addInfo( Messages.format(RefactoringCoreMessages.DelegateCreator_cannot_create_delegate_for_type, BasicElementLabels.getJavaElementName(((AbstractTypeDeclaration) declaration).getName().getIdentifier())), null); } } if (!addedDelegate) { fSource.getASTRewrite().remove(declaration, delete); removeImportsOf= declaration; } if (removeImportsOf != null && fSource != fTarget) fSource.getImportRemover().registerRemovedNode(removeImportsOf); ASTNode node= fTarget.getASTRewrite().createStringPlaceholder(sources[i], declaration.getNodeType()); List<BodyDeclaration> container= containerRewrite.getRewrittenList(); int insertionIndex= ASTNodes.getInsertionIndex((BodyDeclaration) node, container); containerRewrite.insertAt(node, insertionIndex, add); } return result; } private BodyDeclaration[] getASTMembers(RefactoringStatus status) throws JavaModelException { BodyDeclaration[] result= new BodyDeclaration[fMembersToMove.length]; for (int i= 0; i < fMembersToMove.length; i++) { IMember member= fMembersToMove[i]; ASTNode node= NodeFinder.perform(fSource.getRoot(), member.getNameRange()); result[i]= (BodyDeclaration) ASTNodes.getParent(node, BodyDeclaration.class); //Fix for bug 42383: exclude multiple VariableDeclarationFragments ("int a=1, b=2") //ReferenceAnalyzer#visit(FieldDeclaration node) depends on fragments().size() != 1 ! if (result[i] instanceof FieldDeclaration && ((FieldDeclaration) result[i]).fragments().size() != 1) { status.addFatalError(RefactoringCoreMessages.MoveMembersRefactoring_multi_var_fields); return result; } } //Sorting members is important for field declarations referring to previous fields. Arrays.sort(result, new Comparator<BodyDeclaration>() { public int compare(BodyDeclaration o1, BodyDeclaration o2) { return o1.getStartPosition() - o2.getStartPosition(); } }); return result; } private RefactoringStatus initialize(JavaRefactoringArguments extended) { String handle= extended.getAttribute(JavaRefactoringDescriptorUtil.ATTRIBUTE_INPUT); if (handle != null) { final IJavaElement element= JavaRefactoringDescriptorUtil.handleToElement(extended.getProject(), handle, false); if (element == null || !element.exists() || element.getElementType() != IJavaElement.TYPE) return JavaRefactoringDescriptorUtil.createInputFatalStatus(element, getProcessorName(), IJavaRefactorings.MOVE_STATIC_MEMBERS); else { fDestinationType= (IType) element; fDestinationTypeName= fDestinationType.getFullyQualifiedName(); } } else return RefactoringStatus.createFatalErrorStatus(Messages.format(RefactoringCoreMessages.InitializableRefactoring_argument_not_exist, JavaRefactoringDescriptorUtil.ATTRIBUTE_INPUT)); final String delegate= extended.getAttribute(ATTRIBUTE_DELEGATE); if (delegate != null) { fDelegateUpdating= Boolean.valueOf(delegate).booleanValue(); } else return RefactoringStatus.createFatalErrorStatus(Messages.format(RefactoringCoreMessages.InitializableRefactoring_argument_not_exist, ATTRIBUTE_DELEGATE)); final String deprecate= extended.getAttribute(ATTRIBUTE_DEPRECATE); if (deprecate != null) { fDelegateDeprecation= Boolean.valueOf(deprecate).booleanValue(); } else return RefactoringStatus.createFatalErrorStatus(Messages.format(RefactoringCoreMessages.InitializableRefactoring_argument_not_exist, ATTRIBUTE_DEPRECATE)); int count= 1; final List<IJavaElement> elements= new ArrayList<IJavaElement>(); String attribute= JavaRefactoringDescriptorUtil.ATTRIBUTE_ELEMENT + count; final RefactoringStatus status= new RefactoringStatus(); while ((handle= extended.getAttribute(attribute)) != null) { final IJavaElement element= JavaRefactoringDescriptorUtil.handleToElement(extended.getProject(), handle, false); if (element == null || !element.exists()) status.merge(JavaRefactoringDescriptorUtil.createInputWarningStatus(element, getProcessorName(), IJavaRefactorings.MOVE_STATIC_MEMBERS)); else elements.add(element); count++; attribute= JavaRefactoringDescriptorUtil.ATTRIBUTE_ELEMENT + count; } fMembersToMove= elements.toArray(new IMember[elements.size()]); if (elements.isEmpty()) return JavaRefactoringDescriptorUtil.createInputFatalStatus(null, getProcessorName(), IJavaRefactorings.MOVE_STATIC_MEMBERS); IJavaProject project= null; if (fMembersToMove.length > 0) project= fMembersToMove[0].getJavaProject(); fPreferences= JavaPreferencesSettings.getCodeGenerationSettings(project); if (!status.isOK()) return status; return new RefactoringStatus(); } public String getDelegateUpdatingTitle(boolean plural) { if (plural) return RefactoringCoreMessages.DelegateMethodCreator_keep_original_moved_plural_member; else return RefactoringCoreMessages.DelegateMethodCreator_keep_original_moved_singular_member; } ///////////////// //CODINGSPECTATOR ///////////////// public JavaRefactoringDescriptor getOriginalRefactoringDescriptor() { return createDescriptor(); } public String getDescriptorID() { return IJavaRefactorings.MOVE_STATIC_MEMBERS; } }